package main

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

var (
	NAME        = "匿名"
	SERVER_HOST = "127.0.0.1"
	LOCAL_HOST  = "127.0.0.1"
	CONN        *websocket.Conn
	CONN_LIST   []*websocket.Conn
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func StrToMd5(str string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(str)))
}

func refreshLocalIP() {
	addrs, _ := net.InterfaceAddrs()
	for _, address := range addrs {
		address_str := address.String()
		if address_str[:7] == "192.168" {
			address_str_list := strings.Split(address_str, "/")
			LOCAL_HOST = address_str_list[0]
			break
		}
	}
}

func refreshServerHostReq(host string, client *http.Client) {
	res, err := client.Get(fmt.Sprintf("http://%s:9023/check", host))
	if err == nil {
		body_data := map[string]interface{}{}
		err = json.NewDecoder(res.Body).Decode(&body_data)
		if err == nil {
			ip_md5, ok := body_data["ip"].(string)
			if ok {
				if ip_md5 == StrToMd5(host) {
					SERVER_HOST = host
				}
			}
		}
	}
}

func refreshServerHost() {
	// 检查服务器主机
	check_host_list := []string{}
	host_list := strings.Split(LOCAL_HOST, ".")
	host := host_list[0] + "." + host_list[1] + "." + host_list[2] + "."
	for i := 2; i < 255; i++ {
		check_host_list = append(check_host_list, host+fmt.Sprintf("%d", i))
	}
	timeout := 2 * time.Second
	client := &http.Client{Timeout: timeout}
	for _, host := range check_host_list {
		go refreshServerHostReq(host, client)
	}
}

func startServer() {
	// 启动服务器
	gin.SetMode(gin.ReleaseMode)
	app := gin.Default()
	app.GET("/check", func(ctx *gin.Context) {
		ctx.JSON(200, gin.H{
			"ip": StrToMd5(LOCAL_HOST),
		})
	})
	app.GET("/ws", func(ctx *gin.Context) {
		conn, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
		if err != nil {
			return
		}
		defer conn.Close()
		CONN_LIST = append(CONN_LIST, conn)
		for {
			_, message, err := conn.ReadMessage()
			if err != nil {
				break
			}
			for _, conn := range CONN_LIST {
				if conn != nil {
					conn.WriteMessage(websocket.TextMessage, message)
				}
			}
		}
	})
	app.Run(":9023")
}

func connect() {
	// 连接服务器
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)
	for {
		// WebSocket 服务器地址
		url := fmt.Sprintf("ws://%s:9023/ws", SERVER_HOST)
		fmt.Println("尝试连接服务器:", url)
		time.Sleep(1 * time.Second)
		conn, _, err := websocket.DefaultDialer.Dial(url, nil)
		if err != nil {
			fmt.Println("连接服务器失败:", err)
			continue
		}
		CONN = conn
		defer conn.Close()
		// 连接websocket
		fmt.Println("连接服务器成功")
		done := make(chan struct{})
		defer close(done)
		for {
			_, message, err := conn.ReadMessage()
			if err != nil {
				return
			}
			fmt.Println(string(message))
		}
	}
}

func send() {
	// 发送消息
	for {
		var input string
		fmt.Print("> ")
		fmt.Scanln(&input)
		if input == "exit" {
			os.Exit(0)
		}
		if input != "" {
			send_message := fmt.Sprintf("%s[%s]: %s", LOCAL_HOST, NAME, input)
			err := CONN.WriteMessage(websocket.TextMessage, []byte(send_message))
			if err != nil {
				go connect()
			}
		}
	}
}

func main() {
	isServer := false
	if len(os.Args) > 1 {
		if os.Args[1] == "s" {
			isServer = true
			if len(os.Args) > 2 {
				NAME = os.Args[2]
			}
		} else {
			NAME = os.Args[1]
		}
	}
	refreshLocalIP()
	if isServer {
		SERVER_HOST = LOCAL_HOST
		go startServer()
	} else {
		refreshServerHost()
	}
	go connect()
	send()
}
